﻿using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Encodings;
using Org.BouncyCastle.Crypto.Engines;
using Org.BouncyCastle.Crypto.Generators;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;

namespace Basic.Base.Encryption;

public class BCRsaAlgorithm : IAsymmetricAlgorithm
{
    private byte[] PublicKey;
    private byte[] PrivateKey;

    private string PublicKeyStr;
    private string PrivateKeyStr;

    public BCRsaAlgorithm() { }

    public BCRsaAlgorithm(string publicKey, string privateKey)
    {
        PublicKeyStr = publicKey;
        PrivateKeyStr = privateKey;
    }

    public BCRsaAlgorithm(byte[] publicKey, byte[] privateKey)
    {
        PublicKey = publicKey;
        PrivateKey = privateKey;
    }

    #region 

    public byte[] Encrypt(byte[] rawData)
    {
        using TextReader reader = new StringReader(PublicKeyStr);
        using PemReader pem = new PemReader(reader);
        var keyPair = pem.ReadObject() as RsaKeyParameters;
        // 加密数据使用 PKCS1 格式封装
        Pkcs1Encoding pkcs1 = new Pkcs1Encoding(new RsaEngine());
        // 此处 false 为解密，且标明使用私钥
        pkcs1.Init(true, keyPair);
        // 此处需注意一次性处理的数据长度不能大于密钥
        return pkcs1.ProcessBlock(rawData, 0, rawData.Length);
    }

    public byte[] Decrypt(byte[] encryptionData)
    {
        using TextReader reader = new StringReader(PrivateKeyStr);
        using PemReader pem = new PemReader(reader);
        // 因私钥中包含了公钥，故此处为获取密钥对
        var keyPair = pem.ReadObject() as AsymmetricCipherKeyPair;
        // 加密数据使用 PKCS1 格式封装
        var pkcs1 = new Pkcs1Encoding(new RsaEngine());
        // 此处 false 为解密，且标明使用私钥
        pkcs1.Init(false, keyPair.Private); //keyPair.Private
        // 此处需注意一次性处理的数据长度不能大于密钥
        return pkcs1.ProcessBlock(encryptionData, 0, encryptionData.Length);
    }

    public byte[] SignData(byte[] encryptionData)
    {
        throw new NotImplementedException();
    }

    public bool VerifyData(byte[] encryptionData, byte[] signData)
    {
        throw new NotImplementedException();
    }

    #endregion

    #region 

    public string Decrypt(string encryptionString)
    {
        var encryptionData = Decrypt(Convert.FromBase64String(encryptionString));
        return Encoding.UTF8.GetString(encryptionData);
    }

    public string Encrypt(string rawString)
    {
        var encryptionData = Encrypt(Encoding.UTF8.GetBytes(rawString));
        return Convert.ToBase64String(encryptionData);
    }

    public string SignData(string encryptionData)
    {
        throw new NotImplementedException();
    }

    public bool VerifyData(string encryptionData, string signData)
    {
        throw new NotImplementedException();
    }

    #endregion

    public (string PublicKey, string PrivateKey) GenerateKey()
    {
        // 生成密钥对
        RsaKeyPairGenerator generator = new RsaKeyPairGenerator();
        generator.Init(new KeyGenerationParameters(new SecureRandom(), 256));
        AsymmetricCipherKeyPair keys = generator.GenerateKeyPair();

        // 输出私钥
        using TextWriter textWriter = new StringWriter();
        using PemWriter pemWriter = new PemWriter(textWriter);
        pemWriter.WriteObject(keys.Private);
        pemWriter.Writer.Flush();
        string privateKey = textWriter.ToString();

        // 输出公钥
        using TextWriter textpubWriter = new StringWriter();
        using PemWriter pempubWriter = new PemWriter(textpubWriter);
        pempubWriter.WriteObject(keys.Public);
        pempubWriter.Writer.Flush();
        string publicKey = textpubWriter.ToString();

        return (publicKey, privateKey);
    }

    #region Dispose()

    private bool disposedValue;

    protected virtual void Dispose(bool disposing)
    {
        if (!disposedValue)
        {
            if (disposing)
            {
                // TODO: 释放托管状态(托管对象)
            }
            // TODO: 将大型字段设置为 null
            disposedValue = true;
        }
    }

    public void Dispose()
    {
        // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
        Dispose(disposing: true);
        GC.SuppressFinalize(this);
    }

    #endregion

}